#include <iostream>

#include "atom.h"
#include "bind.h"
#include "input.h"
#include "predicates.h"
#include "prover.h"
#include "system.h"
#include "tuple.h"

class clear : public OnceProver {
predicateName("clear")

  bool proveOnce () {
    std::cout << "\x01B[2J\x01B[0;0H"; // ANSI escape sequence
    return true;
  }

  void set (Tuple&, System&) {
  }
};

ProverFactoryRegistrar<clear, Atom::ID, 1> clearRegistrar;

class dump : public OnceProver {
predicateName("dump")

  bool proveOnce () {
    for(std::vector<pNode>::iterator p = tuple->nodes.begin () + 1; p
        < tuple->nodes.end (); p++)
      std::cout << p->dump ();
    return true;
  }

  Tuple *tuple;
  void set (Tuple &t, System&) {
    tuple = &t;
  }
};

ProverFactoryRegistrar<dump, Tuple::ID> dumpRegistrar;

class homeDir : public OnceBindTupleProver {
predicateName("home.dir")

  bool proveOnce () {
    return binder.bind (*tuple->nodes[1], *new String (Input::singlogPath),
        system->trail);
  }
};

ProverFactoryRegistrar<homeDir, Tuple::ID, 2> homeDirRegistrar;

class load : public OnceBindTupleProver {
predicateName("load")

  bool proveOnce () {
    return system->load (tuple->nodes[1].node->display ());
  }
};

ProverFactoryRegistrar<load, Tuple::ID, 2> loadRegistrar;

class put : public OnceProver {
predicateName("put")

  bool proveOnce () {
    std::cout << tuple->nodes[1].display ();
    return true;
  }

  Tuple *tuple;
  void set (Tuple &t, System&) {
    tuple = &t;
  }
};

ProverFactoryRegistrar<put, Tuple::ID, 2> putRegistrar;

class readCall : public OnceBindTupleProver {
predicateName("read")

  bool proveOnce () {
    std::string input;
    std::cin >> input;
    if(tuple->nodes.size () >= 2) {
      if(!binder.bind (*tuple->nodes[1], *new String (input), system->trail))
        return false; // Bind failed
    }
    return true; // All other cases success
  }
};

ProverFactoryRegistrar<readCall, Tuple::ID> readRegistrar;

class writeCall : public OnceProver {
predicateName("write")

  bool proveOnce () {
    for(std::vector<pNode>::iterator p = tuple->nodes.begin () + 1; p
        < tuple->nodes.end (); p++)
      std::cout << p->display () << ' ';
    return true;
  }

  Tuple *tuple;
  void set (Tuple &t, System&) {
    tuple = &t;
  }
};

ProverFactoryRegistrar<writeCall, Tuple::ID> writeRegistrar;
